﻿#include "WinRTSockTests.h"
#include <ppltasks.h>
#include <mutex>
#include <condition_variable>
#include "winrtsock.h"
#include "DoubangoHelpers.h"

using namespace doubango_rt::BackEnd;

using namespace WinRTSock_RuntimeComponents_Test;
using namespace Platform;
using namespace Concurrency;
using namespace Windows::Foundation;
using namespace Windows::Storage::Streams;

const int ipv4StreamPort = 27015;
const int ipv6StreamPort = 27016;
const int ipv4DatagramPort = 27017;
const int ipv6DatagramPort = 27018;
const int ipv4StreamBindPort = 27019;
const int ipv4DatagramBindPort = 27020;
const auto ipv4HostName = "127.0.0.1";
const auto ipv4HostAddress = "127.0.0.1";
const auto ipv6HostName = "0000:0000:0000:0000:0000:0000:0000:0001";
const auto ipv6WideHostName = L"0000:0000:0000:0000:0000:0000:0000:0001";
const auto ipv6ShortHostName = "::1";
const auto ipv6HostAddress = "::1";
const auto ipv6ShortWideHostName = L"::1";
//const auto ipv4BestSourceExpected = "10.10.9.57";
//const auto ipv6BestSourceExpected = "10.10.9.57";

/*
NOTE: Complete test function should:
Test the correct functions, including the ones that call the function that was rewritten
Document failure conditions using additional tests
Checks the correct HRESULT for a fail condition (map to WSA HRESULTS if possible)
Checks that any WSA events are being raised where appropriate
*/
WinRTSockTests::WinRTSockTests()
{
	this->TestFixtureInit();
}
void WinRTSockTests::TestFixtureInit()
{
	this->ipv4StreamListener = ref new StreamSocketListener();
	this->ipv4StreamListener->ConnectionReceived += ref new TypedEventHandler<StreamSocketListener^, StreamSocketListenerConnectionReceivedEventArgs^>(this, &WinRTSockTests::OnConnection);
	this->ipv4StreamListener->BindServiceNameAsync(ipv4StreamPort.ToString());

	this->ipv6StreamListener = ref new StreamSocketListener();
	this->ipv6StreamListener->ConnectionReceived += ref new TypedEventHandler<StreamSocketListener^, StreamSocketListenerConnectionReceivedEventArgs^>(this, &WinRTSockTests::OnConnection);
	this->ipv6StreamListener->BindEndpointAsync(ref new HostName(ref new Platform::String(ipv6WideHostName)), ipv6StreamPort.ToString());

	this->ipv4DatagramListener = ref new DatagramSocket();
	this->ipv4DatagramListener->MessageReceived += ref new TypedEventHandler<DatagramSocket^, DatagramSocketMessageReceivedEventArgs^>(this, &WinRTSockTests::OnMessageReceived);
	this->ipv4DatagramListener->BindServiceNameAsync(ipv4DatagramPort.ToString());

	this->ipv6DatagramListener = ref new DatagramSocket();
	this->ipv6DatagramListener->MessageReceived += ref new TypedEventHandler<DatagramSocket^, DatagramSocketMessageReceivedEventArgs^>(this, &WinRTSockTests::OnMessageReceived);
	this->ipv6DatagramListener->BindEndpointAsync(ref new HostName(ref new Platform::String(ipv6WideHostName)), ipv6DatagramPort.ToString());
}

void WinRTSockTests::TestInit()
{
}

void WinRTSockTests::TestCleanup()
{
}


void WinRTSockTests::OnConnection(StreamSocketListener^ listener, StreamSocketListenerConnectionReceivedEventArgs^ object)
{
	StreamSocket^ socket = object->Socket;
	DataReader^ reader = ref new DataReader(object->Socket->InputStream);
	DataReaderLoadOperation^ loadOp = reader->LoadAsync(4);
	loadOp->Completed = ref new AsyncOperationCompletedHandler<UINT>
		([=](IAsyncOperation<UINT>^ operation, AsyncStatus status)
	{
		auto bytesRead = operation->GetResults();
		auto str = reader->ReadString(bytesRead);
		if (str->Equals(ref new Platform::String(L"Echo")))
		{
			DataWriter^ writer = ref new DataWriter(socket->OutputStream);
			writer->WriteString(str);
			writer->StoreAsync();
		}
	});
}
void WinRTSockTests::OnMessageReceived(DatagramSocket^ socket, DatagramSocketMessageReceivedEventArgs^ object)
{
	DataReader^ reader = object->GetDataReader();
	auto str = reader->ReadString(4);
	if (str->Equals(ref new Platform::String(L"Echo")))
	{
		DataWriter^ writer = ref new DataWriter(socket->OutputStream);
		writer->WriteString(str);
		//writer->StoreAsync(); // In the MessageReceived handler in the DatagramSocketContainer.Send method, we are only calling WriteString, not StoreAsync. StoreAsync throws an exception and appears to not be necessary.
	}
}

IAsyncOperation<Boolean>^ WinRTSockTests::SIPConnectTest()
{
	return create_async([=]() -> bool
	{
		this->TestInit();

		SipService::SetCodecs(rt_tdav_codec_id_t::tdav_codec_id_all);
		SipService^ sipService = ref new SipService();

		//sipService->SipConfig->DisplayName = "John Doe";						//Change this
		//sipService->SipConfig->ImpuUri = "sip:2229871234567@sip2sip.info";		//Change this
		//sipService->SipConfig->ImpiString = "2229871234567";					//Change this. Number must match previous line
		//sipService->SipConfig->Password = "password";
		//sipService->SipConfig->EarlyIMS = true;
		//sipService->SipConfig->RealmUri = "sip2sip.info";
		//sipService->SipConfig->ProxyHost = "proxy.sipthor.net";
		//sipService->SipConfig->ProxyPort = 5060;
		//sipService->SipConfig->Transport = doubango_rt::BackEnd::SipNetworkTransport::TCP;

		sipService->SipConfig->DisplayName = "Chris Carsella";						
		sipService->SipConfig->ImpuUri = "sip:amadeus@sip2sip.info";		
		sipService->SipConfig->ImpiString = "amadeus@sip2sip.info";					
		sipService->SipConfig->Password = "password";
		sipService->SipConfig->EarlyIMS = true;
		sipService->SipConfig->RealmUri = "sip2sip.info";
		sipService->SipConfig->ProxyHost = "proxy.sipthor.net";
		sipService->SipConfig->ProxyPort = 5060;
		sipService->SipConfig->Transport = doubango_rt::BackEnd::SipNetworkTransport::UDP;

		sipService->SipConfig->PushNotificationUri = "nullptr";	// (App.Current as BogheApp.App).PushChannelUri != null ? (App.Current as BogheApp.App).PushChannelUri.ToString() : "nullptr";
		sipService->SipConfig->UserAgent = "IM - client / OMA1.0 Boghe - Windows 8.1 / v1.0.0.0";//String.Format("IM - client / OMA1.0 Boghe - {0} / v{ 1 }", TARGET_OS, System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);
		
		bool result = false;
		if (sipService->Stop(false))
		{
			if (sipService->Start())
			{
				result = sipService->Register();
				if (result)
				{
					result = false;
					HANDLE h = ::CreateEventEx(NULL, NULL, 0, EVENT_ALL_ACCESS);
					for (int i = 0; !result && i < 20; i++)
					{
						::WaitForSingleObjectEx(h, 100, false);
						SipSessionState state = sipService->RegistrationState;
						result = state == SipSessionState::Connected;
					}
					::CloseHandle(h);
				}
			}
		}

		this->TestCleanup();
		return result;
	});
}

IAsyncOperation<Boolean>^ WinRTSockTests::CreateStreamSocketTest()
{
	return create_async([=]() -> bool
	{
		this->TestInit();
		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		HRESULT hr = socket == INVALID_SOCKET ? E_FAIL : S_OK;
		if (SUCCEEDED(hr))
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}

IAsyncOperation<Boolean>^ WinRTSockTests::CreateDatagramSocketTest()
{
	return create_async([=]()
	{
		this->TestInit();
		SOCKET socket = ::socket(0, SOCK_DGRAM, 0);
		HRESULT hr = socket == INVALID_SOCKET ? E_FAIL : S_OK;
		if (SUCCEEDED(hr))
			::closesocket(socket);

		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::CreateInvalidSocketTest()
{
	return create_async([=]()
	{
		this->TestInit();
		SOCKET socket = ::socket(0, INVALID_SOCKET, 0);
		HRESULT hr = socket == INVALID_SOCKET ? E_FAIL : S_OK;
		if (SUCCEEDED(hr))
			::closesocket(socket);

		this->TestCleanup();
		return ::WSAGetLastError() == WSAESOCKTNOSUPPORT;
	});
}

IAsyncOperation<Boolean>^ WinRTSockTests::SockAddrInfoInitWithIpv4Test()
{
	return create_async([=]()
	{
		this->TestInit();
		int ai_family;
		int ai_socktype;
		int ai_protocol;
		struct sockaddr_storage ai_addr;

		HRESULT hr = InitializeSockAddrInfo(ipv4HostName, ipv4StreamPort, AF_INET, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

		if (SUCCEEDED(hr))
		{
			hr = ai_family == AF_INET ? S_OK : E_FAIL;
			if (SUCCEEDED(hr))
				hr = ai_socktype == SOCK_STREAM ? S_OK : E_FAIL;
			if (SUCCEEDED(hr))
				hr = ai_protocol == IPPROTO_TCP ? S_OK : E_FAIL;

			sockaddr_in* sai = (sockaddr_in*)&ai_addr;
			char name[NI_MAXHOST];
			::inet_ntop(AF_INET, (const PIN_ADDR)&sai->sin_addr, name, sizeof(name));
			if (SUCCEEDED(hr))
				hr = strcmp(name, ipv4HostAddress) == 0 ? S_OK : E_FAIL;
			if (SUCCEEDED(hr))
			{
				if (sai->sin_family == AF_INET)
					hr = ::ntohs(sai->sin_port) == ipv4StreamPort ? S_OK : E_FAIL;
				else
					hr = E_FAIL;
			}
		}

		if (SUCCEEDED(hr))
			hr = ::WSAGetLastError();

		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::SockAddrInfoInitWithIpv6Test()
{
	return create_async([=]()
	{
		this->TestInit();
		int ai_family;
		int ai_socktype;
		int ai_protocol;
		struct sockaddr_storage ai_addr;

		HRESULT hr = InitializeSockAddrInfo(ipv6HostName, ipv6StreamPort, AF_INET6, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

		if (SUCCEEDED(hr))
		{
			hr = ai_family == AF_INET6 ? S_OK : E_FAIL;
			if (SUCCEEDED(hr))
				hr = ai_socktype == SOCK_STREAM ? S_OK : E_FAIL;
			if (SUCCEEDED(hr))
				hr = ai_protocol == IPPROTO_TCP ? S_OK : E_FAIL;

			sockaddr_in6* sai = (sockaddr_in6*)&ai_addr;
			char name[NI_MAXHOST];
			if (SUCCEEDED(hr))
			{
				::inet_ntop(AF_INET6, (const PIN_ADDR)&sai->sin6_addr, name, sizeof(name));
				//::inet_ntop6((const PIN_ADDR)&sai->sin6_addr, name, sizeof(name));
			}
			if (SUCCEEDED(hr))
				hr = strcmp(name, ipv6HostAddress) == 0 ? S_OK : E_FAIL;

			if (SUCCEEDED(hr))
			{
				char ip[INET6_ADDRSTRLEN];
				::inet_ntop(ai_family, (const void*)&sai->sin6_addr, ip, INET6_ADDRSTRLEN);
				hr = strcmp(ip, ipv6ShortHostName) == 0 ? S_OK : E_FAIL;
			}

			if (SUCCEEDED(hr))
			{
				if (sai->sin6_family == AF_INET6)
					hr = ::ntohs(sai->sin6_port) == ipv6StreamPort ? S_OK : E_FAIL;
				else
					hr = E_FAIL;
			}
		}

		if (SUCCEEDED(hr))
			hr = ::WSAGetLastError();

		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::SockAddrInfoInitWithHostNameTest()
{
	return create_async([=]()
	{
		this->TestInit();
		int ai_family;
		int ai_socktype;
		int ai_protocol;
		struct sockaddr_storage ai_addr;

		HRESULT hr = InitializeSockAddrInfo("localhost", ipv4StreamPort, AF_INET, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

		if (SUCCEEDED(hr))
		{
			hr = ai_family == AF_INET ? S_OK : E_FAIL;
			if (SUCCEEDED(hr))
				hr = ai_socktype == SOCK_STREAM ? S_OK : E_FAIL;
			if (SUCCEEDED(hr))
				hr = ai_protocol == IPPROTO_TCP ? S_OK : E_FAIL;

			sockaddr_in* sai = (sockaddr_in*)&ai_addr;
			char name[NI_MAXHOST];
			::inet_ntop(AF_INET, (const PIN_ADDR)&sai->sin_addr, name, sizeof(name));
			if (SUCCEEDED(hr))
				hr = strcmp(name, ipv4HostAddress) == 0 ? S_OK : E_FAIL;
			if (SUCCEEDED(hr))
			{
				if (sai->sin_family == AF_INET)
					hr = ::ntohs(sai->sin_port) == ipv4StreamPort ? S_OK : E_FAIL;
				else
					hr = E_FAIL;
			}
		}

		if (SUCCEEDED(hr))
			hr = ::WSAGetLastError();

		this->TestCleanup();
		return hr == S_OK;
	});
}

IAsyncOperation<Boolean>^ WinRTSockTests::GetFamilyWithIpv4Test()
{
	return create_async([=]()
	{
		this->TestInit();

		int family = ::GetFamily(ipv4HostName, ipv4StreamPort);
		HRESULT hr = family == AF_INET ? S_OK : E_FAIL;

		if (SUCCEEDED(hr))
			hr = ::WSAGetLastError();

		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::GetFamilyWithIpv6Test()
{
	return create_async([=]()
	{
		this->TestInit();

		int family = ::GetFamily(ipv6ShortHostName, ipv4StreamPort);
		HRESULT hr = family == AF_INET6 ? S_OK : E_FAIL;

		if (SUCCEEDED(hr))
			hr = ::WSAGetLastError();

		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::GetFamilyWithHostNameTest()
{
	return create_async([=]()
	{
		this->TestInit();

		int family = ::GetFamily("localhost", ipv4StreamPort);
		//GetFamily always returns the first item in the collection. We can only judge wether
		//or not its IPV4 or IPV6.
		HRESULT hr = (family == AF_INET) || (family == AF_INET6) ? S_OK : E_FAIL;

		if (SUCCEEDED(hr))
			hr = ::WSAGetLastError();

		this->TestCleanup();
		return hr == S_OK;
	});
}

IAsyncOperation<Boolean>^ WinRTSockTests::ConnectStreamSocketWithIpv4Test()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		if (socket != INVALID_SOCKET)
		{
			HANDLE evt = ::CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
			::WSASetEvent(evt);
			::WSAEventSelect(socket, evt, FD_ALL_EVENTS);
			WSANETWORKEVENTS netEvt;

			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;

			hr = InitializeSockAddrInfo(ipv4HostName, ipv4StreamPort, AF_INET, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
				hr = ::ConnectTo(socket, &ai_addr);

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();

			if (SUCCEEDED(hr))
			{
				::WSAEnumNetworkEvents(socket, NULL, &netEvt);
				hr = netEvt.lNetworkEvents & FD_CONNECT ? S_OK : E_FAIL;
				if (SUCCEEDED(hr))
					hr = netEvt.lNetworkEvents & FD_WRITE ? S_OK : E_FAIL;
			}
			::CloseHandle(evt);
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);

		this->TestCleanup();
		return hr == S_OK;
	});
}

IAsyncOperation<Boolean>^ WinRTSockTests::ConnectDatagramSocketWithIpv4Test()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();
		SOCKET socket = ::socket(0, SOCK_DGRAM, 0);
		if (socket != INVALID_SOCKET)
		{
			HANDLE evt = ::CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
			::WSASetEvent(evt);
			::WSAEventSelect(socket, evt, FD_ALL_EVENTS);
			WSANETWORKEVENTS netEvt;

			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;

			hr = InitializeSockAddrInfo(ipv4HostName, ipv4DatagramPort, AF_INET, SOCK_DGRAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
			{
				hr = ::ConnectTo(socket, &ai_addr);
				if (SUCCEEDED(hr))
					hr = HRESULT_FROM_WIN32(::WaitForSingleObjectEx(evt, 1000, 0));
			}

			if (SUCCEEDED(hr))
			{
				::WSAEnumNetworkEvents(socket, NULL, &netEvt);
				//Datagrams never raise FD_CONNECT. FD_WRITE is always raised.
				hr = netEvt.lNetworkEvents & FD_WRITE ? S_OK : E_FAIL;
			}
			::CloseHandle(evt);
		}
		else
			hr = E_FAIL;
		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}

IAsyncOperation<Boolean>^ WinRTSockTests::ConnectStreamSocketWithIpv6Test()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		if (socket != INVALID_SOCKET)
		{
			HANDLE evt = ::CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
			::WSASetEvent(evt);
			::WSAEventSelect(socket, evt, FD_ALL_EVENTS);
			WSANETWORKEVENTS netEvt;

			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;

			hr = InitializeSockAddrInfo(ipv6ShortHostName, ipv6StreamPort, AF_INET6, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
				hr = ::ConnectTo(socket, &ai_addr);

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();

			if (SUCCEEDED(hr))
			{
				::WSAEnumNetworkEvents(socket, NULL, &netEvt);
				hr = netEvt.lNetworkEvents & FD_CONNECT ? S_OK : E_FAIL;
				if (SUCCEEDED(hr))
					hr = netEvt.lNetworkEvents & FD_WRITE ? S_OK : E_FAIL;
			}
			::CloseHandle(evt);
		}
		else
			hr = E_FAIL;
		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::ConnectDatagramSocketWithIpv6Test()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_DGRAM, 0);
		if (socket != INVALID_SOCKET)
		{
			HANDLE evt = ::CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
			::WSASetEvent(evt);
			::WSAEventSelect(socket, evt, FD_ALL_EVENTS);
			WSANETWORKEVENTS netEvt;

			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;

			hr = InitializeSockAddrInfo(ipv6ShortHostName, ipv6DatagramPort, AF_INET6, SOCK_DGRAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
				hr = ::ConnectTo(socket, &ai_addr);

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();

			if (SUCCEEDED(hr))
			{
				::WSAEnumNetworkEvents(socket, NULL, &netEvt);
				//Datagrams never raise FD_CONNECT. FD_WRITE is always raised.
				hr = netEvt.lNetworkEvents & FD_WRITE ? S_OK : E_FAIL;
			}
			::CloseHandle(evt);
		}
		else
			hr = E_FAIL;
		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::ConnectStreamSocketWithHostNameTest()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		if (socket != INVALID_SOCKET)
		{
			HANDLE evt = ::CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
			::WSASetEvent(evt);
			::WSAEventSelect(socket, evt, FD_ALL_EVENTS);
			WSANETWORKEVENTS netEvt;

			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;

			hr = InitializeSockAddrInfo("localhost", ipv4StreamPort, AF_INET, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
				hr = ::ConnectTo(socket, &ai_addr);

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();

			if (SUCCEEDED(hr))
			{
				::WSAEnumNetworkEvents(socket, NULL, &netEvt);
				hr = netEvt.lNetworkEvents & FD_CONNECT ? S_OK : E_FAIL;
				if (SUCCEEDED(hr))
					hr = netEvt.lNetworkEvents & FD_WRITE ? S_OK : E_FAIL;
			}
			::CloseHandle(evt);
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::ConnectDatagramSocketWithHostNameTest()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_DGRAM, 0);
		if (socket != INVALID_SOCKET)
		{
			HANDLE evt = ::CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
			::WSASetEvent(evt);
			::WSAEventSelect(socket, evt, FD_ALL_EVENTS);
			WSANETWORKEVENTS netEvt;

			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;

			hr = InitializeSockAddrInfo("localhost", ipv4DatagramPort, AF_INET, SOCK_DGRAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
				hr = ::ConnectTo(socket, &ai_addr);

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();

			if (SUCCEEDED(hr))
			{
				::WSAEnumNetworkEvents(socket, NULL, &netEvt);
				hr = netEvt.lNetworkEvents & FD_WRITE ? S_OK : E_FAIL;
			}
			::CloseHandle(evt);
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}

IAsyncOperation<Boolean>^ WinRTSockTests::GetSockNameWithIpv4StreamSocketTest()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		if (socket != INVALID_SOCKET)
		{
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			int len = sizeof(sockaddr_storage);
			struct sockaddr_storage ai_nameaddr;

			hr = InitializeSockAddrInfo(ipv4HostName, ipv4StreamPort, AF_INET, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);
			if (SUCCEEDED(hr))
			{
				hr = connect((SOCKET)socket, reinterpret_cast<sockaddr*>(&ai_addr), 0);
				int error = ::WSAGetLastError();
				if (FAILED(hr) && WSAEWOULDBLOCK == error) //per winsock
				{
					fd_set fds;
					struct timeval timetowait;
					int timeout = 500;

					timetowait.tv_sec = (timeout / 1000);
					timetowait.tv_usec = (timeout % 1000) * 1000;

					FD_ZERO(&fds);
					FD_SET(socket, &fds);

					int ret = select(socket, &fds, &fds, 0, &timetowait);
					hr = (ret == 2) ? S_OK : hr = E_FAIL;
				}
			}

			if (SUCCEEDED(hr))
				hr = ::getsockname(socket, reinterpret_cast<sockaddr*>(&ai_nameaddr), &len);

			if (SUCCEEDED(hr))
			{
				if (ai_nameaddr.ss_family == AF_INET)
				{
					sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(&ai_nameaddr);
					char ip[INET_ADDRSTRLEN];
					inet_ntop(ai_nameaddr.ss_family, (const void*)&sa->sin_addr, ip, INET_ADDRSTRLEN);
					hr = strcmp(ip, ipv4HostName) == 0 ? S_OK : E_FAIL;
				}
				else
				{
					hr = E_FAIL;
				}
			}

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::GetSockNameWithIpv4DatagramSocketTest()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		sockaddr_storage* addr = new sockaddr_storage();
		int len = sizeof(sockaddr_storage);

		SOCKET socket = ::socket(0, SOCK_DGRAM, 0);
		if (socket != INVALID_SOCKET)
		{
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			struct sockaddr_storage ai_nameaddr;

			hr = InitializeSockAddrInfo(ipv4HostName, ipv4DatagramPort, AF_INET, SOCK_DGRAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
			{
				hr = connect((SOCKET)socket, (sockaddr*)&ai_addr, 0);
				int error = ::WSAGetLastError();
				if (FAILED(hr) && WSAEWOULDBLOCK == error) //per winsock
				{
					fd_set fds;
					struct timeval timetowait;
					int timeout = 500;

					timetowait.tv_sec = (timeout / 1000);
					timetowait.tv_usec = (timeout % 1000) * 1000;

					FD_ZERO(&fds);
					FD_SET(socket, &fds);

					int ret = select(socket, &fds, &fds, 0, &timetowait);
					hr = (ret == 2) ? S_OK : hr = E_FAIL;
				}
			}
			if (SUCCEEDED(hr))
				::getsockname(socket, (sockaddr*)&ai_nameaddr, &len);

			if (SUCCEEDED(hr))
			{
				if (ai_nameaddr.ss_family == AF_INET)
				{
					sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(&ai_nameaddr);
					char ip[INET_ADDRSTRLEN];
					inet_ntop(ai_nameaddr.ss_family, (const void*)&sa->sin_addr, ip, INET_ADDRSTRLEN);
					hr = strcmp(ip, ipv4HostName) == 0 ? S_OK : E_FAIL;
				}
				else
				{
					hr = E_FAIL;
				}
			}

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::GetSockNameWithIpv6StreamSocketTest()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		if (socket != INVALID_SOCKET)
		{
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			int len = sizeof(sockaddr_storage);
			struct sockaddr_storage ai_nameaddr;

			hr = InitializeSockAddrInfo(ipv6ShortHostName, ipv6StreamPort, AF_INET6, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
			{
				hr = connect((SOCKET)socket, (sockaddr*)&ai_addr, 0);
				int error = ::WSAGetLastError();
				if (FAILED(hr) && WSAEWOULDBLOCK == error) //per winsock
				{
					fd_set fds;
					struct timeval timetowait;
					int timeout = 500;

					timetowait.tv_sec = (timeout / 1000);
					timetowait.tv_usec = (timeout % 1000) * 1000;

					FD_ZERO(&fds);
					FD_SET(socket, &fds);

					int ret = select(socket, &fds, &fds, 0, &timetowait);
					hr = (ret == 2) ? S_OK : hr = E_FAIL;
				}
			}
			if (SUCCEEDED(hr))
				::getsockname(socket, (sockaddr*)&ai_nameaddr, &len);

			if (SUCCEEDED(hr))
			{
				if (ai_nameaddr.ss_family == AF_INET6)
				{
					sockaddr_in6* sa = reinterpret_cast<sockaddr_in6*>(&ai_nameaddr);
					char ip[INET6_ADDRSTRLEN];
					inet_ntop(ai_nameaddr.ss_family, (const void*)&sa->sin6_addr, ip, INET6_ADDRSTRLEN);
					hr = strcmp(ip, ipv6ShortHostName) == 0 ? S_OK : E_FAIL;
				}
				else
				{
					hr = E_FAIL;
				}
			}

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::GetSockNameWithIpv6DatagramSocketTest()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		sockaddr_storage* addr = new sockaddr_storage();
		int len = sizeof(sockaddr_storage);

		SOCKET socket = ::socket(0, SOCK_DGRAM, 0);
		if (socket != INVALID_SOCKET)
		{
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			struct sockaddr_storage ai_nameaddr;

			hr = InitializeSockAddrInfo(ipv6ShortHostName, ipv6DatagramPort, AF_INET6, SOCK_DGRAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
			{
				hr = connect((SOCKET)socket, (sockaddr*)&ai_addr, 0);
				int error = ::WSAGetLastError();
				if (FAILED(hr) && WSAEWOULDBLOCK == error) //per winsock
				{
					fd_set fds;
					struct timeval timetowait;
					int timeout = 500;

					timetowait.tv_sec = (timeout / 1000);
					timetowait.tv_usec = (timeout % 1000) * 1000;

					FD_ZERO(&fds);
					FD_SET(socket, &fds);

					int ret = select(socket, &fds, &fds, 0, &timetowait);
					hr = (ret == 2) ? S_OK : hr = E_FAIL;
				}
			}
			if (SUCCEEDED(hr))
				::getsockname(socket, (sockaddr*)&ai_nameaddr, &len);

			if (SUCCEEDED(hr))
			{
				if (ai_nameaddr.ss_family == AF_INET6)
				{
					sockaddr_in6* sa = reinterpret_cast<sockaddr_in6*>(&ai_nameaddr);
					char ip[INET6_ADDRSTRLEN];
					inet_ntop(ai_nameaddr.ss_family, (const void*)&sa->sin6_addr, ip, INET6_ADDRSTRLEN);
					hr = strcmp(ip, ipv6ShortHostName) == 0 ? S_OK : E_FAIL;
				}
				else
				{
					hr = E_FAIL;
				}
			}

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::GetSockNameWithHostNameStreamSocketTest()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		if (socket != INVALID_SOCKET)
		{
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			int len = sizeof(sockaddr_storage);
			struct sockaddr_storage ai_nameaddr;

			hr = InitializeSockAddrInfo("localhost", ipv4StreamPort, AF_INET, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
			{
				hr = connect((SOCKET)socket, (sockaddr*)&ai_addr, 0);
				int error = ::WSAGetLastError();
				if (FAILED(hr) && WSAEWOULDBLOCK == error) //per winsock
				{
					fd_set fds;
					struct timeval timetowait;
					int timeout = 500;

					timetowait.tv_sec = (timeout / 1000);
					timetowait.tv_usec = (timeout % 1000) * 1000;

					FD_ZERO(&fds);
					FD_SET(socket, &fds);

					int ret = select(socket, &fds, &fds, 0, &timetowait);
					hr = (ret == 2) ? S_OK : hr = E_FAIL;
				}
			}
			if (SUCCEEDED(hr))
				hr = ::getsockname(socket, (sockaddr*)&ai_nameaddr, &len);

			if (SUCCEEDED(hr))
			{
				if (ai_nameaddr.ss_family == AF_INET)
				{
					sockaddr_in* sa4 = reinterpret_cast<sockaddr_in*>(&ai_nameaddr);
					char ip[INET_ADDRSTRLEN];
					inet_ntop(ai_nameaddr.ss_family, (const void*)&sa4->sin_addr, ip, INET_ADDRSTRLEN);
					hr = strcmp(ip, ipv4HostName) == 0 ? S_OK : E_FAIL;
				}
				else if (ai_nameaddr.ss_family == AF_INET6)
				{
					sockaddr_in6* sa6 = reinterpret_cast<sockaddr_in6*>(&ai_nameaddr);
					char ip[INET6_ADDRSTRLEN];
					inet_ntop(ai_nameaddr.ss_family, (const void*)&sa6->sin6_addr, ip, INET6_ADDRSTRLEN);
					hr = strcmp(ip, ipv6ShortHostName) == 0 ? S_OK : E_FAIL;
				}
				else
				{
					hr = E_FAIL;
				}
			}

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
/*
TODO: DatagramSocket connect doesn't actually connect until it wants to send something, so these will always
pass, but we need to find out what the local address is on a connected datagram socket before any data has been sent.
*/
IAsyncOperation<Boolean>^ WinRTSockTests::GetSockNameWithHostNameDatagramSocketTest()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		sockaddr_storage* addr = new sockaddr_storage();
		int len = sizeof(sockaddr_storage);

		SOCKET socket = ::socket(0, SOCK_DGRAM, 0);
		if (socket != INVALID_SOCKET)
		{
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			struct sockaddr_storage ai_nameaddr;

			hr = InitializeSockAddrInfo("localhost", ipv4DatagramPort, AF_INET, SOCK_DGRAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
			{
				hr = connect((SOCKET)socket, (sockaddr*)&ai_addr, 0);
				int error = ::WSAGetLastError();
				if (FAILED(hr) && WSAEWOULDBLOCK == error) //per winsock
				{
					fd_set fds;
					struct timeval timetowait;
					int timeout = 500;

					timetowait.tv_sec = (timeout / 1000);
					timetowait.tv_usec = (timeout % 1000) * 1000;

					FD_ZERO(&fds);
					FD_SET(socket, &fds);

					int ret = select(socket, &fds, &fds, 0, &timetowait);
					hr = (ret == 2) ? S_OK : hr = E_FAIL;
				}
			}
			if (SUCCEEDED(hr))
				hr = ::getsockname(socket, (sockaddr*)&ai_nameaddr, &len);

			if (SUCCEEDED(hr))
			{
				if (ai_nameaddr.ss_family == AF_INET)
				{
					sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(&ai_nameaddr);
					char ip[INET_ADDRSTRLEN];
					inet_ntop(ai_nameaddr.ss_family, (const void*)&sa->sin_addr, ip, INET_ADDRSTRLEN);
					// TODO: What is the expected result?
					hr = strcmp(ip, ipv4HostName) == 0 ? S_OK : E_FAIL;
				}
				else if (ai_nameaddr.ss_family == AF_INET6)
				{
					sockaddr_in6* sa6 = (sockaddr_in6*)&ai_nameaddr;
					char ip[INET6_ADDRSTRLEN];
					inet_ntop(ai_nameaddr.ss_family, (const void*)&sa6->sin6_addr, ip, INET6_ADDRSTRLEN);
					// TODO: What is the expected result?
					hr = strcmp(ip, ipv6ShortHostName) == 0 ? S_OK : E_FAIL;
				}
				else
				{
					hr = E_FAIL;
				}
			}

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}

/*
TODO:
Rework this test. It should better describe the expected usage and result.
This test shouldn't fail if the socket isn't connected.
*/
IAsyncOperation<Boolean>^ WinRTSockTests::GetHostNameTest()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		char host[NI_MAXHOST];
		::gethostname(host, NI_MAXHOST);
		// Now that we have the host, use it to try to connect to our local server. 
		// This may be an invalid assertion
		// Note: this will fail if the local server socket isn't listening
		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		if (socket != INVALID_SOCKET)
		{
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;

			hr = InitializeSockAddrInfo(host, ipv4StreamPort, AF_INET, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);
			if (SUCCEEDED(hr))
				hr = ::ConnectTo(socket, &ai_addr);

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}


IAsyncOperation<Boolean>^ WinRTSockTests::GetSockIpAndPortWithIpv4Test()
{
	return create_async([=]()
	{
		this->TestInit();

		struct sockaddr_storage ai_addr;
		char ip[INET6_ADDRSTRLEN];
		int port;
		int ai_family;
		int ai_socktype;
		int ai_protocol;
		//hr = InitializeSockAddrInfo(ipv4HostName, ipv4StreamPort, AF_INET, SOCK_STREAM, &sa.sin_addr, &sa.sin_family,, &s, &ai_protocol);
		HRESULT hr = InitializeSockAddrInfo(ipv4HostName, ipv4StreamPort, AF_INET, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);
		//sockaddr_in sa;
		//sa.sin_addr = ai_addr.
		if (SUCCEEDED(hr))
			hr = GetSocketIpAndPort((sockaddr*)&ai_addr, ip, INET6_ADDRSTRLEN, &port);
		if (SUCCEEDED(hr))
			hr = strcmp(ip, ipv4HostName) == 0 ? S_OK : E_FAIL;
		if (SUCCEEDED(hr))
			hr = port == ipv4StreamPort ? S_OK : E_FAIL;

		if (SUCCEEDED(hr))
			hr = ::WSAGetLastError();

		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::GetSockIpAndPortWithIpv6Test()
{
	return create_async([=]()
	{
		this->TestInit();

		struct sockaddr_storage ai_addr;
		char ip[INET6_ADDRSTRLEN];
		int port;
		int ai_family;
		int ai_socktype;
		int ai_protocol;

		HRESULT hr = InitializeSockAddrInfo(ipv6ShortHostName, ipv6StreamPort, AF_INET6, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);
		if (SUCCEEDED(hr))
			hr = GetSocketIpAndPort((sockaddr*)&ai_addr, ip, INET6_ADDRSTRLEN, &port);
		if (SUCCEEDED(hr))
			hr = strcmp(ip, ipv6ShortHostName) == 0 ? S_OK : E_FAIL;
		if (SUCCEEDED(hr))
			hr = port == ipv6StreamPort ? S_OK : E_FAIL;

		if (SUCCEEDED(hr))
			hr = ::WSAGetLastError();

		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::GetSockIpAndPortWithHostNameTest()
{
	return create_async([=]()
	{
		this->TestInit();

		struct sockaddr_storage ai_addr;
		char ip[INET6_ADDRSTRLEN];
		int port;
		int ai_family;
		int ai_socktype;
		int ai_protocol;

		HRESULT hr = InitializeSockAddrInfo("localhost", ipv4StreamPort, AF_INET, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);
		//tnet_getsockipandport uses getnameinfo under the sheets. Unfortunately, WinRT has no way of providing this information.
		if (SUCCEEDED(hr))
			hr = GetSocketIpAndPort((sockaddr*)&ai_addr, ip, INET6_ADDRSTRLEN, &port);
		if (SUCCEEDED(hr))
			hr = strcmp(ip, ipv4HostAddress) == 0 ? S_OK : E_FAIL;
		if (SUCCEEDED(hr))
			hr = port == ipv4StreamPort ? S_OK : E_FAIL;

		if (SUCCEEDED(hr))
			hr = ::WSAGetLastError();

		this->TestCleanup();
		return hr == S_OK;
	});
}

IAsyncOperation<Boolean>^ WinRTSockTests::GetPeerNameWithIpv4StreamSocketTest()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		if (socket != INVALID_SOCKET)
		{
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			int len = sizeof(sockaddr_storage);
			struct sockaddr_storage ai_nameaddr;

			hr = InitializeSockAddrInfo(ipv4HostName, ipv4StreamPort, AF_INET, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
			{
				hr = connect((SOCKET)socket, (sockaddr*)&ai_addr, 0);
				int error = ::WSAGetLastError();
				if (FAILED(hr) && WSAEWOULDBLOCK == error) //per winsock
				{
					fd_set fds;
					struct timeval timetowait;
					int timeout = 500;

					timetowait.tv_sec = (timeout / 1000);
					timetowait.tv_usec = (timeout % 1000) * 1000;

					FD_ZERO(&fds);
					FD_SET(socket, &fds);

					int ret = select(socket, &fds, &fds, 0, &timetowait);
					hr = (ret == 2) ? S_OK : hr = E_FAIL;
				}
			}
			if (SUCCEEDED(hr))
				hr = ::getpeername(socket, (sockaddr*)&ai_nameaddr, &len);

			if (SUCCEEDED(hr))
			{
				if (ai_nameaddr.ss_family == AF_INET)
				{
					sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(&ai_nameaddr);
					char ip[INET_ADDRSTRLEN];
					inet_ntop(ai_nameaddr.ss_family, (const void*)&sa->sin_addr, ip, INET_ADDRSTRLEN);
					hr = strcmp(ip, ipv4HostName) == 0 ? S_OK : E_FAIL;
					if (SUCCEEDED(hr))
						hr = ::ntohs(sa->sin_port) == (unsigned short)ipv4StreamPort ? S_OK : E_FAIL;
				}
				else
				{
					hr = E_FAIL;
				}
			}

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::GetPeerNameWithIpv4DatagramSocketTest()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		sockaddr_storage* addr = new sockaddr_storage();
		int len = sizeof(sockaddr_storage);

		SOCKET socket = ::socket(0, SOCK_DGRAM, 0);
		if (socket != INVALID_SOCKET)
		{
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			struct sockaddr_storage ai_nameaddr;

			hr = InitializeSockAddrInfo(ipv4HostName, ipv4DatagramPort, AF_INET, SOCK_DGRAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
			{
				hr = connect((SOCKET)socket, (sockaddr*)&ai_addr, 0);
				int error = ::WSAGetLastError();
				if (FAILED(hr) && WSAEWOULDBLOCK == error) //per winsock
				{
					fd_set fds;
					struct timeval timetowait;
					int timeout = 500;

					timetowait.tv_sec = (timeout / 1000);
					timetowait.tv_usec = (timeout % 1000) * 1000;

					FD_ZERO(&fds);
					FD_SET(socket, &fds);

					int ret = select(socket, &fds, &fds, 0, &timetowait);
					hr = (ret == 2) ? S_OK : hr = E_FAIL;
				}
			}
			if (SUCCEEDED(hr))
				::getpeername(socket, (sockaddr*)&ai_nameaddr, &len);

			if (SUCCEEDED(hr))
			{
				if (ai_nameaddr.ss_family == AF_INET)
				{
					sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(&ai_nameaddr);
					char ip[INET_ADDRSTRLEN];
					inet_ntop(ai_nameaddr.ss_family, (const void*)&sa->sin_addr, ip, INET_ADDRSTRLEN);
					hr = strcmp(ip, ipv4HostName) == 0 ? S_OK : E_FAIL;
					if (SUCCEEDED(hr))
						hr = ::ntohs(sa->sin_port) == (unsigned short)ipv4DatagramPort ? S_OK : E_FAIL;
				}
				else
				{
					hr = E_FAIL;
				}
			}

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::GetPeerNameWithIpv6StreamSocketTest()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		if (socket != INVALID_SOCKET)
		{
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			int len = sizeof(sockaddr_storage);
			struct sockaddr_storage ai_nameaddr;

			hr = InitializeSockAddrInfo(ipv6ShortHostName, ipv6StreamPort, AF_INET6, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
			{
				hr = connect((SOCKET)socket, (sockaddr*)&ai_addr, 0);
				int error = ::WSAGetLastError();
				if (FAILED(hr) && WSAEWOULDBLOCK == error) //per winsock
				{
					fd_set fds;
					struct timeval timetowait;
					int timeout = 500;

					timetowait.tv_sec = (timeout / 1000);
					timetowait.tv_usec = (timeout % 1000) * 1000;

					FD_ZERO(&fds);
					FD_SET(socket, &fds);

					int ret = select(socket, &fds, &fds, 0, &timetowait);
					hr = (ret == 2) ? S_OK : hr = E_FAIL;
				}
			}
			if (SUCCEEDED(hr))
				::getpeername(socket, (sockaddr*)&ai_nameaddr, &len);

			if (SUCCEEDED(hr))
			{
				if (ai_nameaddr.ss_family == AF_INET6)
				{
					sockaddr_in6* sa = reinterpret_cast<sockaddr_in6*>(&ai_nameaddr);
					char ip[INET6_ADDRSTRLEN];
					inet_ntop(ai_nameaddr.ss_family, (const void*)&sa->sin6_addr, ip, INET6_ADDRSTRLEN);
					hr = strcmp(ip, ipv6ShortHostName) == 0 ? S_OK : E_FAIL;
					if (SUCCEEDED(hr))
						hr = ::ntohs(sa->sin6_port) == (unsigned short)ipv6StreamPort ? S_OK : E_FAIL;
				}
				else
				{
					hr = E_FAIL;
				}
			}

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::GetPeerNameWithIpv6DatagramSocketTest()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		sockaddr_storage* addr = new sockaddr_storage();
		int len = sizeof(sockaddr_storage);

		SOCKET socket = ::socket(0, SOCK_DGRAM, 0);
		if (socket != INVALID_SOCKET)
		{
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			struct sockaddr_storage ai_nameaddr;

			hr = InitializeSockAddrInfo(ipv6ShortHostName, ipv6DatagramPort, AF_INET6, SOCK_DGRAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);


			if (SUCCEEDED(hr))
			{
				hr = connect((SOCKET)socket, (sockaddr*)&ai_addr, 0);
				int error = ::WSAGetLastError();
				if (FAILED(hr) && WSAEWOULDBLOCK == error) //per winsock
				{
					fd_set fds;
					struct timeval timetowait;
					int timeout = 500;

					timetowait.tv_sec = (timeout / 1000);
					timetowait.tv_usec = (timeout % 1000) * 1000;

					FD_ZERO(&fds);
					FD_SET(socket, &fds);

					int ret = select(socket, &fds, &fds, 0, &timetowait);
					hr = (ret == 2) ? S_OK : hr = E_FAIL;
				}
			}
			if (SUCCEEDED(hr))
				::getpeername(socket, (sockaddr*)&ai_nameaddr, &len);

			if (SUCCEEDED(hr))
			{
				if (ai_nameaddr.ss_family == AF_INET6)
				{
					sockaddr_in6* sa = reinterpret_cast<sockaddr_in6*>(&ai_nameaddr);
					char ip[INET6_ADDRSTRLEN];
					inet_ntop(ai_nameaddr.ss_family, (const void*)&sa->sin6_addr, ip, INET6_ADDRSTRLEN);
					hr = strcmp(ip, ipv6ShortHostName) == 0 ? S_OK : E_FAIL;
					if (SUCCEEDED(hr))
						hr = ::ntohs(sa->sin6_port) == (unsigned short)ipv6DatagramPort ? S_OK : E_FAIL;
				}
				else
				{
					hr = E_FAIL;
				}
			}

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::GetPeerNameWithHostNameStreamSocketTest()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		if (socket != INVALID_SOCKET)
		{
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			int len = sizeof(sockaddr_storage);
			struct sockaddr_storage ai_nameaddr;

			hr = InitializeSockAddrInfo("localhost", ipv4StreamPort, AF_INET, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
			{
				hr = connect((SOCKET)socket, (sockaddr*)&ai_addr, 0);
				int error = ::WSAGetLastError();
				if (FAILED(hr) && WSAEWOULDBLOCK == error) //per winsock
				{
					fd_set fds;
					struct timeval timetowait;
					int timeout = 500;

					timetowait.tv_sec = (timeout / 1000);
					timetowait.tv_usec = (timeout % 1000) * 1000;

					FD_ZERO(&fds);
					FD_SET(socket, &fds);

					int ret = select(socket, &fds, &fds, 0, &timetowait);
					hr = (ret == 2) ? S_OK : hr = E_FAIL;
				}
			}
			if (SUCCEEDED(hr))
				hr = ::getpeername(socket, (sockaddr*)&ai_nameaddr, &len);

			if (SUCCEEDED(hr))
			{
				if (ai_nameaddr.ss_family == AF_INET)
				{
					sockaddr_in* sa4 = reinterpret_cast<sockaddr_in*>(&ai_nameaddr);
					char ip[INET_ADDRSTRLEN];
					inet_ntop(ai_nameaddr.ss_family, (const void*)&sa4->sin_addr, ip, INET_ADDRSTRLEN);
					hr = strcmp(ip, ipv4HostName) == 0 ? S_OK : E_FAIL;
					if (SUCCEEDED(hr))
						hr = ::ntohs(sa4->sin_port) == ipv4StreamPort ? S_OK : E_FAIL;
				}
				else if (ai_nameaddr.ss_family == AF_INET6)
				{
					sockaddr_in6* sa6 = reinterpret_cast<sockaddr_in6*>(&ai_nameaddr);
					char ip[INET6_ADDRSTRLEN];
					inet_ntop(ai_nameaddr.ss_family, (const void*)&sa6->sin6_addr, ip, INET6_ADDRSTRLEN);
					hr = strcmp(ip, ipv6ShortHostName) == 0 ? S_OK : E_FAIL;
					if (SUCCEEDED(hr))
						hr = ::ntohs(sa6->sin6_port) == ipv4StreamPort ? S_OK : E_FAIL;
				}
				else
				{
					hr = E_FAIL;
				}
			}

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();
		}
		else
			hr = E_FAIL;

		this->TestCleanup();
		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		return hr == S_OK;
	});
}

IAsyncOperation<Boolean>^ WinRTSockTests::GetPeerNameWithHostNameDatagramSocketTest()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		sockaddr_storage* addr = new sockaddr_storage();
		int len = sizeof(sockaddr_storage);

		SOCKET socket = ::socket(0, SOCK_DGRAM, 0);
		if (socket != INVALID_SOCKET)
		{
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			struct sockaddr_storage ai_nameaddr;

			hr = InitializeSockAddrInfo("localhost", ipv4StreamPort, AF_INET, SOCK_DGRAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
			{
				hr = connect((SOCKET)socket, (sockaddr*)&ai_addr, 0);
				int error = ::WSAGetLastError();
				if (FAILED(hr) && WSAEWOULDBLOCK == error) //per winsock
				{
					fd_set fds;
					struct timeval timetowait;
					int timeout = 500;

					timetowait.tv_sec = (timeout / 1000);
					timetowait.tv_usec = (timeout % 1000) * 1000;

					FD_ZERO(&fds);
					FD_SET(socket, &fds);

					int ret = select(socket, &fds, &fds, 0, &timetowait);
					hr = (ret == 2) ? S_OK : hr = E_FAIL;
				}
			}
			if (SUCCEEDED(hr))
				hr = ::getpeername(socket, (sockaddr*)&ai_nameaddr, &len);

			if (SUCCEEDED(hr))
			{
				if (ai_nameaddr.ss_family == AF_INET)
				{
					sockaddr_in* sa4 = reinterpret_cast<sockaddr_in*>(&ai_nameaddr);
					char ip[INET_ADDRSTRLEN];
					inet_ntop(ai_nameaddr.ss_family, (const void*)&sa4->sin_addr, ip, INET_ADDRSTRLEN);
					hr = strcmp(ip, ipv4HostName) == 0 ? S_OK : E_FAIL;
					if (SUCCEEDED(hr))
						hr = ::ntohs(sa4->sin_port) == (unsigned short)ipv4StreamPort ? S_OK : E_FAIL;
				}
				else if (ai_nameaddr.ss_family == AF_INET6)
				{
					sockaddr_in6* sa6 = reinterpret_cast<sockaddr_in6*>(&ai_nameaddr);
					char ip[INET6_ADDRSTRLEN];
					inet_ntop(ai_nameaddr.ss_family, (const void*)&sa6->sin6_addr, ip, INET6_ADDRSTRLEN);
					hr = strcmp(ip, ipv6ShortHostName) == 0 ? S_OK : E_FAIL;
					if (SUCCEEDED(hr))
						hr = ::ntohs(sa6->sin6_port) == (unsigned short)ipv4StreamPort ? S_OK : E_FAIL;
				}
				else
				{
					hr = E_FAIL;
				}
			}

			if (SUCCEEDED(hr))
				hr = ::WSAGetLastError();
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}

//IAsyncOperation<Boolean>^ WinRTSockTests::BindDatagramSocketTest()
//{
//	return create_async([=]()
//	{
//		this->TestInit();
//		HRESULT hr = E_FAIL;
//		SOCKET socket = ::socket(AF_INET, SOCK_DGRAM, 0);
//		if (socket != INVALID_SOCKET)
//		{
//			sockaddr_in sai;
//			sai.sin_family = AF_INET;
//			sai.sin_addr.s_addr = INADDR_LOOPBACK;
//			sai.sin_port = htons(ipv4DatagramPort);
//
//			hr = bind(socket, (PSOCKADDR)& sai, sizeof(sai));
//		}
//		if (socket && socket != INVALID_SOCKET)
//			::closesocket(socket);
//		this->TestCleanup();
//		return hr == S_OK;
//	});
//}
//
//IAsyncOperation<Boolean>^ WinRTSockTests::AcceptStreamSocketTest()
//{
//	return create_async([=]()
//	{
//		this->TestInit();
//		HRESULT hr = E_FAIL;
//		//tnet_socket_t* socket = tnet_socket_create_2(ipv4HostName, tnet_port_t(ipv4StreamBindPort), sock_type, tsk_true, tsk_true);
//		//HRESULT hr = socket != nullptr ? S_OK : E_FAIL;
//
//		//if (SUCCEEDED(hr))
//		//{
//		//	hr = socket->fd != INVALID_SOCKET ? S_OK : E_FAIL;
//		//	if (SUCCEEDED(hr))
//		//	{
//		//		::WSAEventSelect(socket->fd, 0, FD_ALL_EVENTS);
//		//		WSANETWORKEVENTS netEvt;
//
//		//		SOCKET client_socket = ::socket(0, sock_type, 0);
//		//		hr = client_socket == INVALID_SOCKET ? E_FAIL : S_OK;
//		//		if (SUCCEEDED(hr))
//		//		{
//		//			::WSAEventSelect(client_socket, 0, FD_ALL_EVENTS);
//		//			int ai_family;
//		//			int ai_socktype;
//		//			int ai_protocol;
//		//			struct sockaddr_storage ai_addr;
//
//		//			hr = InitializeSockAddrInfo(ipv4HostName, ipv4StreamBindPort, AF_INET, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);
//		//			if (SUCCEEDED(hr))
//		//			{
//		//				hr = ::ConnectTo(client_socket, &ai_addr);
//
//		//				::WSAEnumNetworkEvents(socket->fd, NULL, &netEvt);
//		//				hr = netEvt.lNetworkEvents & FD_ACCEPT ? S_OK : E_FAIL;
//		//				if (SUCCEEDED(hr))
//		//				{
//		//					hr = ::WSAGetLastError();
//		//					if (SUCCEEDED(hr))
//		//						hr = accepted ? S_OK : E_FAIL;
//		//				}
//		//			}
//		//		}
//		//		::closesocket((SOCKET)socket->fd);
//		//	}
//		//}
//		//if (socket && socket != INVALID_SOCKET)
//		//	::closesocket(socket);
//		this->TestCleanup();
//		return hr == S_OK;
//	});
//}

IAsyncOperation<Boolean>^ WinRTSockTests::SendStreamSocketWithIpv4Test()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		if (socket != INVALID_SOCKET)
		{
			::WSAEventSelect(socket, 0, FD_ALL_EVENTS);
			WSANETWORKEVENTS netEvt;

			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			UINT32 expectedNumberOfBytesSent = 4;
			UINT32 actualNumberOfBytesSent = 0;

			hr = InitializeSockAddrInfo(ipv4HostName, ipv4StreamPort, AF_INET, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);
			if (SUCCEEDED(hr))
			{
				hr = ::ConnectTo(socket, &ai_addr);
				if (SUCCEEDED(hr))
				{
					actualNumberOfBytesSent = ::send(socket, "Test", expectedNumberOfBytesSent, 0);
					hr = actualNumberOfBytesSent == expectedNumberOfBytesSent ? S_OK : E_FAIL;

					if (SUCCEEDED(hr))
					{
						::WSAEnumNetworkEvents(socket, NULL, &netEvt);
						hr = netEvt.lNetworkEvents & FD_WRITE ? S_OK : E_FAIL;

						if (SUCCEEDED(hr))
							hr = ::WSAGetLastError();
					}
				}
			}

		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::SendToDatagramSocketWithIpv4Test()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_DGRAM, 0);
		if (socket != INVALID_SOCKET)
		{
			::WSAEventSelect(socket, 0, FD_ALL_EVENTS);
			WSANETWORKEVENTS netEvt;

			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			UINT32 expectedNumberOfBytesSent = 4;
			UINT32 actualNumberOfBytesSent = 0;

			hr = InitializeSockAddrInfo(ipv4HostName, ipv4DatagramPort, AF_INET, SOCK_DGRAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
			{
				actualNumberOfBytesSent = ::sendto(socket, "Test", expectedNumberOfBytesSent, 0, (sockaddr*)&ai_addr, 0);
				hr = actualNumberOfBytesSent == expectedNumberOfBytesSent ? S_OK : E_FAIL;
				if (SUCCEEDED(hr))
				{
					::WSAEnumNetworkEvents(socket, NULL, &netEvt);
					hr = netEvt.lNetworkEvents & FD_WRITE ? S_OK : E_FAIL;
					if (SUCCEEDED(hr))
						hr = ::WSAGetLastError();
				}
			}
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::SendStreamSocketWithIpv6Test()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		if (socket != INVALID_SOCKET)
		{
			::WSAEventSelect(socket, 0, FD_ALL_EVENTS);
			WSANETWORKEVENTS netEvt;
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			UINT32 expectedNumberOfBytesSent = 4;
			UINT32 actualNumberOfBytesSent = 0;

			hr = InitializeSockAddrInfo(ipv6ShortHostName, ipv6StreamPort, AF_INET6, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);
			if (SUCCEEDED(hr))
			{
				hr = ::ConnectTo(socket, &ai_addr);
				if (SUCCEEDED(hr))
				{
					actualNumberOfBytesSent = ::send(socket, "Test", expectedNumberOfBytesSent, 0);
					hr = actualNumberOfBytesSent == expectedNumberOfBytesSent ? S_OK : E_FAIL;
					if (SUCCEEDED(hr))
					{
						::WSAEnumNetworkEvents(socket, NULL, &netEvt);
						hr = netEvt.lNetworkEvents & FD_WRITE ? S_OK : E_FAIL;
						if (SUCCEEDED(hr))
							hr = ::WSAGetLastError();
					}
				}
			}
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::SendToDatagramSocketWithIpv6Test()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_DGRAM, 0);
		if (socket != INVALID_SOCKET)
		{
			::WSAEventSelect(socket, 0, FD_ALL_EVENTS);
			WSANETWORKEVENTS netEvt;

			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			UINT32 expectedNumberOfBytesSent = 4;
			UINT32 actualNumberOfBytesSent = 0;

			hr = InitializeSockAddrInfo(ipv6ShortHostName, ipv6DatagramPort, AF_INET6, SOCK_DGRAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
			{
				actualNumberOfBytesSent = ::sendto(socket, "Test", expectedNumberOfBytesSent, 0, (sockaddr*)&ai_addr, 0);
				hr = actualNumberOfBytesSent == expectedNumberOfBytesSent ? S_OK : E_FAIL;
				if (SUCCEEDED(hr))
				{
					::WSAEnumNetworkEvents(socket, NULL, &netEvt);
					hr = netEvt.lNetworkEvents & FD_WRITE ? S_OK : E_FAIL;
					if (SUCCEEDED(hr))
						hr = ::WSAGetLastError();
				}
			}
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}

IAsyncOperation<Boolean>^ WinRTSockTests::WSASendStreamSocketWithIpv4Test()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		if (socket != INVALID_SOCKET)
		{
			::WSAEventSelect(socket, 0, FD_ALL_EVENTS);
			WSANETWORKEVENTS netEvt;

			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			UINT32 expectedNumberOfBytesSent = 4;
			UINT32 actualNumberOfBytesSent = 0;

			hr = InitializeSockAddrInfo(ipv4HostName, ipv4StreamPort, AF_INET, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);
			if (SUCCEEDED(hr))
			{
				hr = ::ConnectTo(socket, &ai_addr);
				if (SUCCEEDED(hr))
				{
					WSABUF buf;
					buf.buf = "Test";
					buf.len = expectedNumberOfBytesSent;

					hr = ::WSASend(socket, &buf, 1, (LPDWORD)&actualNumberOfBytesSent, 0, 0, nullptr);
					if (SUCCEEDED(hr))
					{
						::WSAEnumNetworkEvents(socket, NULL, &netEvt);
						hr = netEvt.lNetworkEvents & FD_WRITE ? S_OK : E_FAIL;
						if (SUCCEEDED(hr))
						{
							hr = actualNumberOfBytesSent == expectedNumberOfBytesSent ? S_OK : E_FAIL;
							if (SUCCEEDED(hr))
								hr = ::WSAGetLastError();
						}
					}
				}
			}
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::WSASendToDatagramSocketWithIpv4Test()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_DGRAM, 0);
		if (socket != INVALID_SOCKET)
		{
			::WSAEventSelect(socket, 0, FD_ALL_EVENTS);
			WSANETWORKEVENTS netEvt;

			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			UINT32 expectedNumberOfBytesSent = 4;
			UINT32 actualNumberOfBytesSent = 0;

			hr = InitializeSockAddrInfo(ipv4HostName, ipv4DatagramPort, AF_INET, SOCK_DGRAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
			{
				WSABUF buf;
				buf.buf = "Test";
				buf.len = expectedNumberOfBytesSent;

				hr = ::WSASendTo(socket, &buf, 1, (LPDWORD)&actualNumberOfBytesSent, 0, (sockaddr*)&ai_addr, 0, 0, nullptr);
				if (SUCCEEDED(hr))
				{
					::WSAEnumNetworkEvents(socket, NULL, &netEvt);
					hr = netEvt.lNetworkEvents & FD_WRITE ? S_OK : E_FAIL;
					if (SUCCEEDED(hr))
					{
						hr = actualNumberOfBytesSent == expectedNumberOfBytesSent ? S_OK : E_FAIL;
						if (SUCCEEDED(hr))
							hr = ::WSAGetLastError();
					}
				}
			}
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::WSASendStreamSocketWithIpv6Test()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		if (socket != INVALID_SOCKET)
		{
			::WSAEventSelect(socket, 0, FD_ALL_EVENTS);
			WSANETWORKEVENTS netEvt;

			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			UINT32 expectedNumberOfBytesSent = 4;
			UINT32 actualNumberOfBytesSent = 0;

			hr = InitializeSockAddrInfo(ipv6ShortHostName, ipv6StreamPort, AF_INET6, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
			{
				hr = ::ConnectTo(socket, &ai_addr);
				if (SUCCEEDED(hr))
				{
					WSABUF buf;
					buf.buf = "Test";
					buf.len = expectedNumberOfBytesSent;

					hr = ::WSASend(socket, &buf, 1, (LPDWORD)&actualNumberOfBytesSent, 0, 0, nullptr);
					if (SUCCEEDED(hr))
					{
						::WSAEnumNetworkEvents(socket, NULL, &netEvt);
						hr = netEvt.lNetworkEvents & FD_WRITE ? S_OK : E_FAIL;
						if (SUCCEEDED(hr))
						{
							hr = actualNumberOfBytesSent == expectedNumberOfBytesSent ? S_OK : E_FAIL;
							if (SUCCEEDED(hr))
								hr = ::WSAGetLastError();
						}
					}
				}
			}
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::WSASendToDatagramSocketWithIpv6Test()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_DGRAM, 0);
		if (socket != INVALID_SOCKET)
		{
			::WSAEventSelect(socket, 0, FD_ALL_EVENTS);
			WSANETWORKEVENTS netEvt;

			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;
			UINT32 expectedNumberOfBytesSent = 4;
			UINT32 actualNumberOfBytesSent = 0;

			hr = InitializeSockAddrInfo(ipv6ShortHostName, ipv6DatagramPort, AF_INET6, SOCK_DGRAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
			{
				WSABUF buf;
				buf.buf = "Test";
				buf.len = expectedNumberOfBytesSent;

				hr = ::WSASendTo(socket, &buf, 1, (LPDWORD)&actualNumberOfBytesSent, 0, (sockaddr*)&ai_addr, 0, 0, nullptr);
				if (SUCCEEDED(hr))
				{
					::WSAEnumNetworkEvents(socket, NULL, &netEvt);
					hr = netEvt.lNetworkEvents & FD_WRITE ? S_OK : E_FAIL;
					if (SUCCEEDED(hr))
					{
						hr = actualNumberOfBytesSent == expectedNumberOfBytesSent ? S_OK : E_FAIL;
						if (SUCCEEDED(hr))
							hr = ::WSAGetLastError();
					}
				}
			}
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}

// TODO: Implement these tests
IAsyncOperation<Boolean>^ WinRTSockTests::RecvStreamSocketWithIpv4Test()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		if (socket != INVALID_SOCKET)
		{
			::WSAEventSelect(socket, 0, FD_ALL_EVENTS);
			WSANETWORKEVENTS netEvt;

			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;

			hr = InitializeSockAddrInfo(ipv4HostName, ipv4StreamPort, AF_INET, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);
			if (SUCCEEDED(hr))
			{
				hr = ::ConnectTo(socket, &ai_addr);
				if (SUCCEEDED(hr))
				{
					WSABUF buf;
					buf.buf = "Echo";
					buf.len = 4;
					DWORD numberOfBytesSent;

					hr = ::WSASend(socket, &buf, 1, &numberOfBytesSent, 0, 0, nullptr);
					if (SUCCEEDED(hr))
					{
						::WSAEnumNetworkEvents(socket, NULL, &netEvt);
						hr = netEvt.lNetworkEvents & FD_WRITE ? S_OK : E_FAIL;
						if (SUCCEEDED(hr))
							hr = ::WSAGetLastError();
					}
				}
			}
		}
		else
			hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::RecvFromDatagramSocketWithIpv4Test()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_DGRAM, 0);
		if (socket != INVALID_SOCKET)
		{
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;

			hr = InitializeSockAddrInfo(ipv4HostName, ipv4DatagramPort, AF_INET, SOCK_DGRAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
				hr = ::sendto(socket, "Echo", 4, 0, (sockaddr*)&ai_addr, 0);


		}
		else
			hr = E_FAIL;

		if (SUCCEEDED(hr))
			hr = ::WSAGetLastError();


		// TODO: complete assertions
		//hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::RecvStreamSocketWithIpv6Test()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_STREAM, 0);
		if (socket != INVALID_SOCKET)
		{
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;

			hr = InitializeSockAddrInfo(ipv6ShortHostName, ipv6StreamPort, AF_INET6, SOCK_STREAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
				hr = ::ConnectTo(socket, &ai_addr);

			if (SUCCEEDED(hr))
				hr = ::send(socket, "Echo", 4, 0);

		}
		else
			hr = E_FAIL;

		if (SUCCEEDED(hr))
			hr = ::WSAGetLastError();


		// TODO: complete assertions
		//hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}
IAsyncOperation<Boolean>^ WinRTSockTests::RecvFromDatagramSocketWithIpv6Test()
{
	return create_async([=]()
	{
		HRESULT hr = S_OK;
		this->TestInit();

		SOCKET socket = ::socket(0, SOCK_DGRAM, 0);
		if (socket != INVALID_SOCKET)
		{
			int ai_family;
			int ai_socktype;
			int ai_protocol;
			struct sockaddr_storage ai_addr;

			hr = InitializeSockAddrInfo(ipv6ShortHostName, ipv6DatagramPort, AF_INET6, SOCK_DGRAM, &ai_addr, &ai_family, &ai_socktype, &ai_protocol);

			if (SUCCEEDED(hr))
				hr = ::sendto(socket, "Echo", 4, 0, (sockaddr*)&ai_addr, 0);

		}
		else
			hr = E_FAIL;

		if (SUCCEEDED(hr))
			hr = ::WSAGetLastError();


		// TODO: complete assertions
		//hr = E_FAIL;

		if (socket && socket != INVALID_SOCKET)
			::closesocket(socket);
		this->TestCleanup();
		return hr == S_OK;
	});
}

